package zheezes.util.format;

import java.math.BigDecimal;
import java.util.Arrays;

import zheezes.util.ArrayUtil;
import zheezes.util.ByteUtil;


public class NumberFormat {
	public static final int MODE_ASCII = 0;
	public static final int MODE_BCD = 1;
	
	public static final int DIMI = -4;
	public static final int MILLI = -3;
	public static final int MICRO = -2;
	public static final int DECI = -1;
	public static final int UNIT = 0;
	public static final int DECIMAL = 1;
	public static final int HUND = 2;
	public static final int THSD = 3;
	public static final int MYRIA = 4;
	public static final int HUND_THSD = 5;
	public static final int MILLION = 6;
	public static final int TEN_MILLION = 7;
	public static final int HUND_MILLION = 8;
	public static final int BILLION = 9;
	public static final int TEN_BILLION = 10;
	public static final int HUND_BILLION = 11;
	public static final int TERA = 12;

	public static final BigDecimal clear(BigDecimal value, int dbit) {
		StringBuilder sb = new StringBuilder(value.toString());
		int idx = sb.indexOf(".");
		if (dbit < 0) {
			idx = idx - dbit;
		} else {
			idx = idx - 1 - dbit;
		}
		if (idx > 0 && idx < sb.length()) {
			sb.setCharAt(idx, '0');
			value = new BigDecimal(sb.toString());
		}
		return value;
	}

	public static final BigDecimal add(BigDecimal value, int dbit, int mod) {
		BigDecimal av = new BigDecimal(mod);
		BigDecimal td = new BigDecimal(10);
		if (dbit < 0) {
			switch (dbit) {
			case DIMI:
				av = av.divide(td);
			case MILLI:
				av = av.divide(td);
			case MICRO:
				av = av.divide(td);
			case DECI:
				av = av.divide(td);
			}
		}
		if (dbit > 0) {
			switch (dbit) {
			case BILLION:
				av = av.multiply(td);
			case HUND_MILLION:
				av = av.multiply(td);
			case TEN_MILLION:
				av = av.multiply(td);
			case MILLION:
				av = av.multiply(td);
			case HUND_THSD:
				av = av.multiply(td);
			case MYRIA:
				av = av.multiply(td);
			case THSD:
				av = av.multiply(td);
			case HUND:
				av = av.multiply(td);
			case DECIMAL:
				av = av.multiply(td);
			}
		}
		return value.add(av);
	}

	public static final BigDecimal set(BigDecimal value, int dbit, int mod) {
		value = clear(value, dbit);
		value = add(value, dbit, mod);
		return value;
	}

	public static final int get(BigDecimal value, int dbit) {
		String str = value.toString();
		int idx = str.indexOf(".");
		if (dbit < 0) {
			idx = idx - dbit;
		} else {
			idx = idx - 1 - dbit;
		}
		
		if (idx < 0 || idx >= str.length()) {
			return 0; // if vlaue = 100, there is 0 in 1000
		}
		return ByteUtil.ctoa(str.charAt(idx));
	}

	public static final BigDecimal setByte(BigDecimal value, int dbit, byte mod) {
		int hv = (mod & 0xF0) >> 4;
		int lv = mod & 0x0F;

		value = set(value, dbit, lv);
		value = set(value, dbit + 1, hv);
		return value;
	}

	public static final byte getByte(BigDecimal value, int dbit) {
		byte lb = (byte) get(value, dbit);
		byte hb = (byte) get(value, dbit + 1);
		
		return (byte) ((hb << 4) | (lb & 0x0F));
	}
	
	public static int getBytes(byte[] buf, int offset, BigDecimal value, int dbit, int num, int mode) {
		int idx = offset;
		for (int i = 0; i < num; i++) {
			byte v = getByte(value, dbit + i * 2);
			switch (mode) {
			case MODE_BCD:
				v = ByteUtil.binToBcd(v);
				break;
			default:
			}
			buf[idx++] = v;
		}
		int len = idx - offset;
		ArrayUtil.reverse(buf, offset, len);
		return len;
	}
	
	public static BigDecimal setBytes(byte[] buf, int offset, int len, int dbit, int mode) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < len; i++) {
			byte v = buf[offset + i];
			switch (mode) {
			case MODE_BCD:
				v = ByteUtil.binToBcd(v);
				break;
			default:
			}
			sb.append(String.format("%02X", v));
		}
		return new BigDecimal(sb.toString()).movePointRight(dbit);
	}

	public static void main(String[] args) {
//		BigDecimal dec = new BigDecimal("123412341234123123412314.56");
//		System.out.println(dec.toString());
////		dec = set(dec, NF_UNIT, 1);
//		dec = setByte(dec, UNIT, (byte) 0x31);
//		System.out.println(dec.toString());
//		System.out.printf("%02X", getByte(dec, DECI));
		byte[] buf = {0x01, 0x02, 0x03, 0x04};
		BigDecimal d = setBytes(buf, 0, buf.length, MICRO, MODE_BCD);
		System.out.println(d.toString());
		int len = getBytes(buf, 0, d, MICRO, 4, MODE_BCD);
		String s = ArrayUtil.sprintf(buf, 0, len, "%02X ");
		System.out.println(s);
	}
}
